/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StdAfx.h"

#include "netbios.h"

//---------------------------------------------------------------------------

typedef struct _ASTAT_{
	ADAPTER_STATUS adapt;
	NAME_BUFFER    nameBuff[MAX_NAME_BUFFERS];
}ASTAT, * PASTAT;

//---------------------------------------------------------------------------

NetBios::NetBios(void)
{
	AdapterName.Empty();

	lanas.length = 0;
	FindGoodLana();
}

NetBios::~NetBios(void)
{
}

//---------------------------------------------------------------------------

bool NetBios::EnumerateLana(void)
{
NCB ncb;
UCHAR uRetCode;

	memset(&ncb, 0, sizeof(ncb));
		ncb.ncb_command  = NCBENUM;
		ncb.ncb_buffer   = (unsigned char*)&lanas;
		ncb.ncb_length   = sizeof(LANA_ENUM);
		uRetCode         = Netbios(&ncb);
	if(uRetCode!=NRC_GOODRET) return false;

	return true;
}

//---------------------------------------------------------------------------

bool NetBios::IsGoodLana(unsigned char lanaNumberIn)
{
NCB ncb;
UCHAR uRetCode;
	// aici ar trebui lansate cereri NCBFINDNAME in care numele sa fie
	// numele masinii locale si la care raspunde sa zice ca este buna
	// dar pentru simplificare trimit reset

	memset(&ncb, 0, sizeof(ncb));
		ncb.ncb_command  = NCBRESET;
		ncb.ncb_lana_num = lanaNumberIn;
		uRetCode         = Netbios(&ncb);
		
	if(uRetCode==NRC_GOODRET) return true;
	return false;
}

//---------------------------------------------------------------------------

bool NetBios::FindGoodLana(void)
{
int i;
bool found;

	goodLana = 0;

	if(!EnumerateLana()) return false;

	found = false;
	for(i=0; i<lanas.length && !found; i++){
		if(IsGoodLana(lanas.lana[i])){
			goodLana = lanas.lana[i];
			found = true;
		}
	}

	return found;
}

//---------------------------------------------------------------------------

CString NetBios::BuildName(CString ipaIn)
{
CString ipa;

	ipa = ipaIn;
	if(ipa.GetLength()>NCBNAMSZ)
		ipa = ipa.Mid(0, NCBNAMSZ);
	while(ipa.GetLength()<NCBNAMSZ)
		ipa = ipa + " ";

	return ipa;
}

//---------------------------------------------------------------------------

void NetBios::SetAddress(CString ipaIn)
{
	AdapterName = BuildName(ipaIn);
}

//---------------------------------------------------------------------------

int NetBios::GetNetBiosInfo(BYTE* buffIn)
{
NCB ncb;
UCHAR uRetCode;
ASTAT Adapter;
errno_t err;
int i;

	if(buffIn==NULL) return -1;

	AdapterName = AdapterName.Trim();
	if(AdapterName.GetLength() >= NCBNAMSZ) return -1;

	memset(&ncb, 0, sizeof(ncb));
		ncb.ncb_command  = NCBRESET;
		ncb.ncb_lana_num = goodLana;
		uRetCode         = Netbios(&ncb);
	if(uRetCode!=NRC_GOODRET) return -1;

	memset(&ncb, 0, sizeof(ncb));
		ncb.ncb_command  = NCBASTAT;
		ncb.ncb_lana_num = goodLana;
		err = strcpy_s((char*)ncb.ncb_callname, NCBNAMSZ, AdapterName);
		if(err!=0) return -1;
		for(i=AdapterName.GetLength(); i<NCBNAMSZ; i++)
			ncb.ncb_callname[i] = ' ';
		ncb.ncb_buffer   = (unsigned char *)&Adapter;
		ncb.ncb_length   = sizeof(Adapter);
		uRetCode         = Netbios(&ncb);
	if(uRetCode!=NRC_GOODRET) return -1;

	for(i=0; i<6; i++)
		buffIn[i] = (BYTE)Adapter.adapt.adapter_address[i];

	for(i=0; i<Adapter.adapt.name_count && i<MAX_NAME_BUFFERS; i++)
		memcpy(&Names[i], &Adapter.nameBuff[i], sizeof(NAME_BUFFER));

	return Adapter.adapt.name_count;
}

//---------------------------------------------------------------------------

CString NetBios::GetNBName(int idx)
{
	char aName[NCBNAMSZ + 1];
	BYTE type;
	CString str;

	str.Empty();
	if(idx<0 || idx>=MAX_NAME_BUFFERS) return str;

	memset(aName, 0, NCBNAMSZ + 1);
	memcpy(aName, Names[idx].name, NCBNAMSZ);

	type = (BYTE)aName[NCBNAMSZ-1];
	if(type!=0)
		aName[NCBNAMSZ-1] = 0;

	str = aName;
	if(Names[idx].name_flags & GROUP_NAME){
		str = GetNetBiosNameGroup(type, str);
	}
	else{
		str = GetNetBiosNameUnique(type, str);
	}

	str += _T(": ");

	str += aName;

	str = str.Trim();

	return str;
}

//---------------------------------------------------------------------------

CString NetBios::GetNetBiosNameUnique(BYTE typeIn, CString nameIn)
{
CString str;

	switch(typeIn){
		case 0x00 :
			str = nameIn.Left(3);
			if(str.CompareNoCase(_T("IS~"))==0) str = "IIS";
			else                                str = "Workstation Service";
			break;

		case 0x01 :
			str = "Messenger Service";
			break;

		case 0x03 :
			str = "Messenger Service";
			break;

		case 0x06 :
			str = "RAS Server Service";
			break;

		case 0x1B :
			str = "Domain Master Browser";
			break;

		case 0x1D :
			str = "Master Browser";
			break;

		case 0x1F :
			str = "NetDDE Service";
			break;

		case 0x20 :
			str = nameIn.Left(14);
			if(str.CompareNoCase(_T("Forte_$ND800ZA"))==0) str = "DCA IrmaLan Gateway Server Service";
			else                                           str = "File Server Service";
			break;

		case 0x21 :
			str = "RAS Client Service";
			break;

		case 0x22 :
			str = "Microsoft Exchange Interchange (MSMail Connector)";
			break;

		case 0x23 :
			str = "Microsoft Exchange Store";
			break;

		case 0x24 :
			str = "Microsoft Exchange Directory";
			break;

		case 0x2B :
			str = "Lotus Notes Server Service";
			break;

		case 0x30 :
			str = "Modem Sharing Server Service";
			break;

		case 0x31 :
			str = "Modem Sharing Client Service";
			break;

		case 0x42 :
			str = "McAffee Anti-virus";
			break;

		case 0x43 :
			str = "SMS Clients Remote Control";
			break;

		case 0x44 :
			str = "SMS Administrators Remote Control Tool";
			break;

		case 0x45 :
			str = "SMS Clients Remote Chat";
			break;

		case 0x46 :
			str = "SMS Clients Remote Transfer";
			break;

		case 0x4C :
			str = "DEC Pathworks TCPIP service on Windows NT";
			break;

		case 0x52 :
			str = "DEC Pathworks TCPIP service on Windows NT";
			break;

		case 0x6A :
			str = "Microsoft Exchange IMC";
			break;

		case 0x87 :
			str = "Microsoft Exchange MTA";
			break;

		case 0xBE :
			str = "Network Monitor Agent";
			break;

		case 0xBF :
			str = "Network Monitor Application";
			break;

		default :
			str.Format(_T("%d"), typeIn);
			break;
	}

	return str;
}

//---------------------------------------------------------------------------

CString NetBios::GetNetBiosNameGroup(BYTE typeIn, CString nameIn)
{
CString str;
	
	switch(typeIn){
		case 0x00 :
			str = "Domain Name";
			break;

		case 0x01 :
			str = "Master Browser";
			break;

		case 0x1C :
			str = nameIn.Left(5);
			if(str.CompareNoCase(_T("INet~"))==0) str = "IIS";
			else                                  str = "Domain Controllers";
			break;

		case 0x1E :
			str = "Browser Service Elections";
			break;

		default :
			str = nameIn.Left(13);
			if(str.CompareNoCase(_T("IRISMULTICAST"))==0) str = "LotusNotes";
			else{
				str = nameIn.Left(14);
				if(str.CompareNoCase(_T("IRISNAMESERVER"))==0) str = "LotusNotes";
				else{
					str.Format(_T("%d"), typeIn);
				}
			}
			break;
	}

	return str;
}

//---------------------------------------------------------------------------

//#define SHAREINFO0 TRUE

bool NetBios::EnumerateShares(void)
{
	NET_API_STATUS res;
#ifdef SHAREINFO0
	SHARE_INFO_0 *shares, *share;
#else
	SHARE_INFO_1 *shares, *share;
#endif
	DWORD er, tr, resume;
	DWORD i;
	MShareInfo shareInfo;

	shareInfoList.Clear();

	CT2W pwsz(AdapterName);
	
	shares = NULL;
	er = tr = resume = 0;
#ifdef SHAREINFO0
	res = NetShareEnum(pwsz, 0, (LPBYTE *)&shares, -1, &er, &tr, &resume);
#else
	res = NetShareEnum(pwsz, 1, (LPBYTE *)&shares, -1, &er, &tr, &resume);
#endif
	if(res==ERROR_SUCCESS || res==ERROR_MORE_DATA){
		share = shares;
		for(i=0; i<er && share!=NULL; i++){
#ifdef SHAREINFO0
			shareInfo.name   = share->shi0_netname;
			shareInfo.type   = 0;
			shareInfo.remark = _T("");
#else
			shareInfo.name   = share->shi1_netname;
			shareInfo.type   = share->shi1_type;
			shareInfo.remark = share->shi1_remark;
#endif
			shareInfoList.Add(&shareInfo);
			share++;
		}
		NetApiBufferFree(shares);
		return true;
	}

	return false;
}

//---------------------------------------------------------------------------
